/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.fresco.samples.showcase.misc;

import com.facebook.common.internal.Preconditions;
import com.facebook.fresco.samples.showcase.ShowcaseApplication;
import com.facebook.fresco.samples.showcase.annotation.NotNull;
import com.facebook.fresco.samples.showcase.annotation.Nullable;
import com.facebook.imageformat.DefaultImageFormats;
import com.facebook.imageformat.ImageFormat;
import ohos.app.Context;
import ohos.data.DatabaseHelper;
import ohos.data.preferences.Preferences;
import ohos.data.preferences.PreferencesFileReadException;
import ohos.utils.net.Uri;

import java.io.Closeable;
import java.util.*;

public class ImageUriProvider {

    private final static String PREF_KEY_CACHE_BREAKING_BY_DEFAULT = "uri_cache_breaking";
    private final static String PREF_KEY_URI_OVERRIDE = "uri_override";

    private final static int RANDOM_URI_MAX_IMAGE_ID = 1000;
    private final static String RANDOM_URI_PATTERN_S = "https://picsum.photos/400/400?random=%d";
    private final static String RANDOM_URI_PATTERN_M = "https://picsum.photos/800/800?random=%d";

    private final static String[] SAMPLE_URIS_LANDSCAPE = new String[]{"https://frescolib.org/static/sample-images/animal_a_%s.jpg", "https://frescolib.org/static/sample-images/animal_b_%s.jpg", "https://frescolib.org/static/sample-images/animal_c_%s.jpg", "https://frescolib.org/static/sample-images/animal_e_%s.jpg", "https://frescolib.org/static/sample-images/animal_f_%s.jpg", "https://frescolib.org/static/sample-images/animal_g_%s.jpg"};

    private final static String[] SAMPLE_URIS_PORTRAIT = new String[]{"https://frescolib.org/static/sample-images/animal_d_%s.jpg", "https://frescolib.org/static/sample-images/animal_d_%s.jpg"};

    private final static String SAMPLE_URI_PJPEG_SLOW = "http://pooyak.com/p/progjpeg/jpegload.cgi?o=1";

    private final static String[] SAMPLE_URIS_LANDSCAPE_PNG = new String[]{"https://frescolib.org/static/sample-images/animal_a.png", "https://frescolib.org/static/sample-images/animal_b.png", "https://frescolib.org/static/sample-images/animal_c.png", "https://frescolib.org/static/sample-images/animal_e.png", "https://frescolib.org/static/sample-images/animal_f.png", "https://frescolib.org/static/sample-images/animal_g.png"};

    private final static String[] SAMPLE_URIS_PORTRAIT_PNG = new String[]{"https://frescolib.org/static/sample-images/animal_d.png", "https://frescolib.org/static/sample-images/animal_d.png"};

    private final static String NON_EXISTING_URI = "https://frescolib.org/static/sample-images/does_not_exist.jpg";

    private final static String SAMPLE_URI_WEBP_STATIC = "https://www.gstatic.com/webp/gallery/2.webp";

    private final static String SAMPLE_URI_WEBP_TRANSLUCENT = "https://www.gstatic.com/webp/gallery3/5_webp_ll.webp";

    private final static String SAMPLE_URI_WEBP_ANIMATED = "https://www.gstatic.com/webp/animated/1.webp";

    private final static String SAMPLE_URI_GIF_PATTERN = "https://frescolib.org/static/sample-images/fresco_logo_anim_full_frames_%s.gif";

    private final static String SAMPLE_URI_GIF_WITH_PAUSE_PATTERN = "https://frescolib.org/static/sample-images/fresco_logo_anim_full_frames_with_pause_%s.gif";

    private final static String[] SAMPLE_URIS_GIFS = new String[]{"https://media2.giphy.com/media/3oge84qhopFbFFkwec/giphy.gif", "https://media3.giphy.com/media/uegrGBitPHtKM/giphy.gif", "https://media0.giphy.com/media/SWd9mTHEMIxQ4/giphy.gif"};

    private final static String SAMPLE_URI_KEYFRAMES = "https://frescolib.org/static/sample-images/animation.keyframes";

    private final static String SAMPLE_URI_SVG = "https://frescolib.org/static/sample-images/fresco_logo_half_transparent.svg";


    private final static Preferences sharedPreferences = new DatabaseHelper(ShowcaseApplication.instance).getPreferences(ImageUriProvider.class.getSimpleName());

    private static String uriOverride = null;


    public String getUriOverride() {
        return sharedPreferences.getString(PREF_KEY_URI_OVERRIDE, null);
    }

    public void setUriOverride(String uriOverride) {
        if (uriOverride == null || uriOverride.isEmpty()) {
            sharedPreferences.delete(PREF_KEY_URI_OVERRIDE).flush();
        } else {
            Preconditions.checkArgument(Uri.parse(uriOverride).isAbsolute(), "URI must be absolute");
            sharedPreferences.
                    putString(PREF_KEY_URI_OVERRIDE, uriOverride).flush();
        }
    }

    /**
     * The orientation of a sample image
     */
    public enum Orientation {
        /**
         * height > width
         */
        PORTRAIT,

        /**
         * width > height
         */
        LANDSCAPE,

        /**
         * Any orientation
         */
        ANY
    }

    /**
     * Indicates whether to perform some action on the URI before returning
     */
    public enum UriModification {

        /**
         * Do not perform any modification
         */
        NONE,

        /**
         * Add a unique parameter to the URI to prevent it to be served from any cache
         */
        CACHE_BREAKER
    }

    public enum ImageSize {
        /**
         * Within ~250x250 px bounds
         */
        XS("xs"),

        /**
         * Within ~450x450 px bounds
         */
        S("s"),

        /**
         * Within ~800x800 px bounds
         */
        M("m"),

        /**
         * Within ~1400x1400 px bounds
         */
        L("l"),

        /**
         * Within ~2500x2500 px bounds
         */
        XL("xl"),

        /**
         * Within ~4096x4096 px bounds
         */
        XXL("xxl");
        private String sizeSuffix;

        ImageSize(String sizeSuffix) {
            this.sizeSuffix = sizeSuffix;
        }
    }

    List<Uri> sampleGifUris = new ArrayList<>();

    {
        for (int i = 0; i < SAMPLE_URIS_GIFS.length; i++) {
            sampleGifUris.add(Uri.parse(SAMPLE_URIS_GIFS[i]));
        }
    }

    private static boolean isShouldBreakCacheByDefault = sharedPreferences.getBoolean(PREF_KEY_CACHE_BREAKING_BY_DEFAULT, false);

    private final Uri nonExistingUri = Uri.parse(NON_EXISTING_URI);

    private Uri create(ImageFormat imageFormat) {
        if (imageFormat == null) {
            imageFormat = DefaultImageFormats.JPEG;
        }
        if (imageFormat == DefaultImageFormats.JPEG)
            return createSampleUri(null, null, null);
        if (imageFormat == DefaultImageFormats.PNG)
            return createPngUri(null, null);
        if (imageFormat == DefaultImageFormats.GIF)
            return createGifUri(null);
        if (imageFormat == DefaultImageFormats.WEBP_SIMPLE)
            return createWebpStaticUri();
        if (imageFormat == DefaultImageFormats.WEBP_EXTENDED_WITH_ALPHA)
            return createWebpTranslucentUri();
        if (imageFormat == DefaultImageFormats.WEBP_ANIMATED)
            return createWebpAnimatedUri();
        //   case KeyframesDecoderExample.IMAGE_FORMAT_KEYFRAMES :return createKeyframesUri();
        return null;
    }

    public static Uri createSampleUri(
            ImageSize imageSize,
            Orientation orientation,
            UriModification urlModification) {

        if (imageSize == null) {
            imageSize = ImageSize.M;
        }

        if (orientation == null) {
            orientation = Orientation.ANY;
        }
        if (urlModification == null) {
            urlModification = UriModification.NONE;
        }

        String fullUri = String.format(randomBaseJpegUri(orientation), imageSize.sizeSuffix);
        return applyOverrideSettings(fullUri, urlModification);
    }

    public List<Uri> createSampleUriSet(
            Orientation orientation,
            UriModification urlModification) {

        if (orientation == null) {
            orientation = Orientation.ANY;
        }
        if (urlModification == null) {
            urlModification = UriModification.NONE;
        }

        String baseUri = randomBaseJpegUri(orientation);
        List<Uri> result = new ArrayList<>();
        result.add(applyOverrideSettings(String.format(baseUri, ImageSize.XS.sizeSuffix), urlModification));
        result.add(applyOverrideSettings(String.format(baseUri, ImageSize.S.sizeSuffix), urlModification));
        result.add(applyOverrideSettings(String.format(baseUri, ImageSize.M.sizeSuffix), urlModification));
        result.add(applyOverrideSettings(String.format(baseUri, ImageSize.L.sizeSuffix), urlModification));
        result.add(applyOverrideSettings(String.format(baseUri, ImageSize.XL.sizeSuffix), urlModification));
        result.add(applyOverrideSettings(String.format(baseUri, ImageSize.XXL.sizeSuffix), urlModification));
        return result;
    }

    private Uri createPJPEGSlow() {
        return applyOverrideSettings(SAMPLE_URI_PJPEG_SLOW, UriModification.NONE);
    }

    public Uri createPngUri(
            Orientation orientation,
            UriModification urlModification) {
        String baseUri = null;
        if (orientation == Orientation.PORTRAIT) {
            baseUri = chooseRandom(SAMPLE_URIS_PORTRAIT_PNG);
        }
        if (orientation == Orientation.LANDSCAPE) {
            baseUri = chooseRandom(SAMPLE_URIS_LANDSCAPE_PNG);
        }
        if (orientation == Orientation.ANY) {
            baseUri = chooseRandom(concat(SAMPLE_URIS_LANDSCAPE_PNG, SAMPLE_URIS_PORTRAIT_PNG));
        }
        return applyOverrideSettings(baseUri, urlModification);
    }

    public Uri createWebpStaticUri() {
        return applyOverrideSettings(SAMPLE_URI_WEBP_STATIC, UriModification.NONE);
    }

    public Uri createWebpTranslucentUri() {
        return applyOverrideSettings(SAMPLE_URI_WEBP_TRANSLUCENT, UriModification.NONE);
    }

    public Uri createWebpAnimatedUri() {
        return applyOverrideSettings(SAMPLE_URI_WEBP_ANIMATED, UriModification.NONE);
    }


    public Uri createGifUri(ImageSize imageSize) {
        return applyOverrideSettings(
                String.format(SAMPLE_URI_GIF_PATTERN, imageSize.sizeSuffix),
                UriModification.NONE);
    }

    public static Uri getNonExistingUri() {
        return Uri.parse(NON_EXISTING_URI);
    }

    private Uri createGifUriWithPause(ImageSize imageSize) {
        return applyOverrideSettings(
                String.format(SAMPLE_URI_GIF_WITH_PAUSE_PATTERN, imageSize.sizeSuffix),
                UriModification.NONE);
    }

    private Uri createKeyframesUri() {
        return applyOverrideSettings(SAMPLE_URI_KEYFRAMES, UriModification.NONE);
    }

    private Uri createSvgUri() {
        return applyOverrideSettings(SAMPLE_URI_SVG, UriModification.NONE);
    }


    private List<Uri> getRandomSampleUris(ImageSize imageSize, int numImages) {
        String uriFormat = null;
        if (imageSize == ImageSize.S) {
            uriFormat = RANDOM_URI_PATTERN_S;
        } else if (imageSize == ImageSize.M) {
            uriFormat = RANDOM_URI_PATTERN_M;
        } else if (imageSize == ImageSize.XS || imageSize == ImageSize.L || imageSize == ImageSize.XL || imageSize == ImageSize.XXL) {
            throw new IllegalArgumentException("Don't have random sample URIs for image size: $imageSize");
        }

        Random random = new Random(0);
        // fix seed for reproducible order
        List<Uri> data = new ArrayList<>();

        for (int i = 0; i < numImages; i++) {
            int imageId = random.nextInt(RANDOM_URI_MAX_IMAGE_ID);
            data.add(Uri.parse(String.format(uriFormat, imageId)));
        }
        return data;
    }

    private List<Uri> getMediaStoreUris(Context context) {
        List<Uri> uris = new ArrayList<>();
        /*
        context.contentResolver.query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                arrayOf(MediaStore.Images.Media._ID),
                null,
                null,
                null) ?.use {
            val dataIndex = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
            while (it.moveToNext()) {
                uris.add(
                        ContentUris.withAppendedId(
                                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                                it.getLong(dataIndex)))
            }
        }
         */
        return uris;
    }

    private static Uri applyOverrideSettings(
            String uriString,
            UriModification urlModification) {
        String uriStringInternal = uriString;
        UriModification urlModificationInternal = urlModification;
        if (isShouldBreakCacheByDefault) {
            urlModificationInternal = UriModification.CACHE_BREAKER;
        }

        String overrideUriString = uriOverride;
        if (overrideUriString != null) {
            uriStringInternal = overrideUriString;
        }

        Uri result = Uri.parse(uriStringInternal);
        if (UriModification.CACHE_BREAKER == urlModificationInternal) {
            result = result.makeBuilder().appendDecodedQueryParam("cache_breaker", UUID.randomUUID().toString()).build();
            /*
            result = result.buildUpon()
                    .appendQueryParameter("cache_breaker", UUID.randomUUID().toString())
                    .build()
             */
        }
        return result;
    }

    private static String randomBaseJpegUri(Orientation orientation) {
        String result = null;
        if (orientation == Orientation.PORTRAIT) {
            result = chooseRandom(SAMPLE_URIS_PORTRAIT);
        } else if (orientation == Orientation.LANDSCAPE) {
            result = chooseRandom(SAMPLE_URIS_LANDSCAPE);
        } else if (orientation == Orientation.ANY) {
            result = chooseRandom(concat(SAMPLE_URIS_LANDSCAPE, SAMPLE_URIS_PORTRAIT));
        }
        return result;
    }

    private static <T> T chooseRandom(T... s) {
        Random random = new Random(System.currentTimeMillis());
        return s[random.nextInt(s.length - 1)];
    }

    public static <T> T[] concat(T[] first, T[] second) {
        T[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }
}
